/*
 * Copyright (C) 2008 CERNET Network Center 
 * dvping/dvmcast/hdvping/hdvmcast series 
 * 
 * Design and coding: 
 *  	Xing Li <xing@cernet.edu.cn> 
 *	Congxiao Bao <congxiao@cernet.edu.cn>
 * 	Jinpeng Jiang <jjp02@mails.tsinghua.edu.cn>
 * 
 * Contributions:
 * 
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 */


#include <FileSystemUtil.h>
#include <cstdlib>
#include <iostream>
using namespace std;
#ifndef WIN32

#include <dirent.h>
#undef __USE_MISC
#endif

namespace System
{
namespace IO
{


FileInfo::FileInfo(const string& fileName)
{
	this->fileName = fileName;
}
u_int32_t FileInfo::GetAttributes()
{
	return File::GetAttributes(fileName);
}
void FileInfo::SetAttributes(u_int32_t attributes)
{
	File::SetAttributes(fileName, attributes);
}

DirectoryInfo FileInfo::GetDirectory()
{
	return DirectoryInfo(DirectoryName());
}
string FileInfo::DirectoryName()
{
	return Path::GetDirectoryName(fileName);
}
bool FileInfo::Exists()
{
	return File::Exists(fileName);
}
string FileInfo::Extension()
{
	return Path::GetExtension(fileName);
}
string FileInfo::FullName()
{
	return Path::GetFullPath(fileName);
}
bool FileInfo::IsReadOnly()
{
	return File::GetAttributes(fileName) & FileAttributes::ReadOnly;
}
int64_t FileInfo::Length()
{
	return File::GetLength(fileName);
}
string FileInfo::Name()
{
	return Path::GetFileName(fileName);
}

DateTime FileInfo::CreationTime()
{
	return File::GetCreationTime(fileName);
}
DateTime FileInfo::CreationTimeUtc()
{
	return File::GetCreationTimeUtc(fileName);
}
DateTime FileInfo::LastAccessTime()
{
	return File::GetLastAccessTime(fileName);
}
DateTime FileInfo::LastAccessTimeUtc()
{
	return File::GetLastAccessTimeUtc(fileName);
}
DateTime FileInfo::LastWriteTime()
{
	return File::GetLastWriteTime(fileName);
}
DateTime FileInfo::LastWriteTimeUtc()
{
	return File::GetLastWriteTimeUtc(fileName);
}
bool FileInfo::Create()
{
	return File::CreateEmptyFile(fileName);
}
bool FileInfo::CopyTo(const string& destFileName, bool overwrite/* = false*/)
{
	return File::Copy(fileName, destFileName, overwrite);
}
bool FileInfo::MoveTo(const string& destFileName)
{
	return File::Move(fileName, destFileName);
}
bool FileInfo::Delete()
{
	return File::Delete(fileName);
}

DirectoryInfo::DirectoryInfo(const string& directory)
{
	this->directory = directory;
}
void DirectoryInfo::LoadDirectory(const string& directory)
{
	this->directory = directory;
}

u_int32_t DirectoryInfo::GetAttributes()
{
	return File::GetAttributes(directory);
}

bool DirectoryInfo::GetParent(DirectoryInfo& directoryInfo)
{
	DirectoryString ds(directory);
	if(ds.GotoParent())
	{
		directoryInfo.LoadDirectory(ds.ToString());
		return true;
	}
	return false;
}
bool DirectoryInfo::GetRoot(DirectoryInfo& root)
{
	string strRoot = Path::GetPathRoot(directory);
	if(strRoot == "")
		return false;
	root.LoadDirectory(strRoot);
	return true;
}
bool DirectoryInfo::Exists()
{
	return Directory::Exists(directory);
}
string DirectoryInfo::FullName()
{
	return Path::GetFullPath(directory);
}
bool DirectoryInfo::IsReadOnly()
{
	return FileAttributes::IsReadOnly(File::GetAttributes(directory));
}
string DirectoryInfo::Name()
{
	return Path::GetFileName(directory);
}

DateTime DirectoryInfo::CreationTime()
{
	return Directory::GetCreationTime(directory);
}
DateTime DirectoryInfo::CreationTimeUtc()
{
	return Directory::GetCreationTimeUtc(directory);
}
DateTime DirectoryInfo::LastAccessTime()
{
	return Directory::GetLastAccessTime(directory);
}
DateTime DirectoryInfo::LastAccessTimeUtc()
{
	return Directory::GetLastAccessTimeUtc(directory);
}
DateTime DirectoryInfo::LastWriteTime()
{
	return Directory::GetLastWriteTime(directory);
}
DateTime DirectoryInfo::LastWriteTimeUtc()
{
	return Directory::GetLastWriteTimeUtc(directory);
}

bool DirectoryInfo::Create(bool recursive/* = false*/)
{
	return Directory::Create(directory, recursive);
}
bool DirectoryInfo::CreateSubDirectory(const string& path, bool recursive/* = false*/)
{
	return Directory::Create(Path::Combine(directory, path), recursive);
}
bool DirectoryInfo::CreateSubDirectory(const string& path, DirectoryInfo& directoryInfo, bool recursive/* = false*/)
{
	return Directory::Create(Path::Combine(directory, path), directoryInfo, recursive);
}
bool DirectoryInfo::Delete(bool recursive/* = false*/)
{
	return Directory::Delete(directory, recursive);
}
bool DirectoryInfo::MoveTo(const string& dest)
{
	return Directory::Move(directory, dest);
}
bool DirectoryInfo::CopyTo(const string& destDir, bool overwrite/* = false*/)
{
	return Directory::Copy(directory, destDir, overwrite);
}






bool FileSystemInfo::IsDirectory(const string& path)
{
	return FileAttributes::IsDirectory(File::GetAttributes(path));
}
bool FileSystemInfo::IsFile(const string& path)
{
	return FileAttributes::IsFile(File::GetAttributes(path));
}

#ifdef WIN32

const string Path::ValidDirectorySeparatorChars("/\\");

bool File::Copy(const string& fromPath, const string& toPath, bool overwrite/* = false*/)
{
	return CopyFile(fromPath.c_str(), toPath.c_str(), overwrite ? FALSE : TRUE) != FALSE;
}
bool File::Delete(const string& path)
{
	return DeleteFile(path.c_str()) != FALSE;
}
bool File::Move(const string& sourceFileName, const string& destFileName)
{
	return MoveFile(sourceFileName.c_str(), destFileName.c_str()) != FALSE;
}
bool File::Exists(const string& path)
{
	WIN32_FIND_DATA wfd;
	if(!GetPathInfo(path, wfd))
		return false;
	if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
		return false;
	return true;
}

u_int32_t File::GetAttributes(const string& path)
{
	return GetFileAttributes(path.c_str());
}
void File::SetAttributes(const string& path, u_int32_t attributes)
{
	SetFileAttributes(path.c_str(), attributes);
}
int64_t File::GetLength(const string& path)
{
	WIN32_FIND_DATA wfd;
	if(!GetPathInfo(path, wfd))
		return -1;
	return (((int64_t)wfd.nFileSizeHigh) << 32) | wfd.nFileSizeLow;
}
DateTime FileSystemInfo::GetCreationTime(const string& path)
{
	DateTime t = GetCreationTimeUtc(path);
	t.ToLocalTime();
	return t;
}
DateTime FileSystemInfo::GetCreationTimeUtc(const string& path)
{
	WIN32_FIND_DATA wfd;
	if(GetPathInfo(path, wfd))
	{
		return DateTime(wfd.ftCreationTime);
	}
	return DateTime::BadTime();
}
DateTime FileSystemInfo::GetLastAccessTime(const string& path)
{
	DateTime t = GetLastAccessTimeUtc(path);
	t.ToLocalTime();
	return t;
}
DateTime FileSystemInfo::GetLastAccessTimeUtc(const string& path)
{
	WIN32_FIND_DATA wfd;
	if(GetPathInfo(path, wfd))
	{
		return DateTime(wfd.ftLastAccessTime);
	}
	return DateTime::BadTime();
}
DateTime FileSystemInfo::GetLastWriteTime(const string& path)
{
	DateTime t = GetLastWriteTimeUtc(path);
	t.ToLocalTime();
	return t;
}
DateTime FileSystemInfo::GetLastWriteTimeUtc(const string& path)
{
	WIN32_FIND_DATA wfd;
	if(GetPathInfo(path, wfd))
	{
		return DateTime(wfd.ftLastWriteTime);
	}
	return DateTime::BadTime();
}

bool FileSystemInfo::GetPathInfo(const string& path, WIN32_FIND_DATA& wfd)
{
	HANDLE hFind = FindFirstFile(path.c_str(), &wfd);
	if(hFind != INVALID_HANDLE_VALUE)
	{
		FindClose(hFind);
		return true;
	}
	return false;
}

bool Directory::Create(const string& path, bool recursive/* = false*/)
{
	if(!recursive)
		return ::CreateDirectory(path.c_str(), NULL) != FALSE;
	DirectoryString ds(path);
	list<DirectoryStringItem>& items = ds.GetInternalItems();
	list<DirectoryStringItem>::const_iterator it = items.begin();
	string existPath;
	for(; it != items.end(); ++it)
	{
		string temp = existPath + it->GetPureText();
		if(!Directory::Exists(temp))
			break;
		existPath = temp + Path::DirectorySeparatorChar;
	}
	for(; it != items.end(); ++it)
	{
		existPath += it->GetPureText();
		if(!::CreateDirectory(existPath.c_str(), NULL))
			return false;
		existPath += Path::DirectorySeparatorChar;
	}
	return true;
}
bool Directory::Create(const string& path, DirectoryInfo& di, bool recursive/* = false*/)
{
	if(Create(path, recursive))
	{
		di.LoadDirectory(path);
		return true;
	}
	return false;
}
bool Directory::Delete(const string& path, bool recursive/* = false*/)
{
	if(recursive)
	{
		vector<string> names;
		if(!Directory::GetFiles(path, names))
			return false;
		for(size_t i = 0; i < names.size(); ++i)
		{
			if(!File::Delete(Path::Combine(path, names[i])))
				return false;
		}
		names.resize(0);
		if(!Directory::GetDirectories(path, names))
			return false;
		for(size_t i = 0; i < names.size(); ++i)
		{
			if(!Directory::Delete(Path::Combine(path, names[i]), recursive))
				return false;
		}
	}
	return RemoveDirectory(path.c_str()) != FALSE;
}
bool Directory::Exists(const string& path)
{
	WIN32_FIND_DATA wfd;
	if(!GetPathInfo(path, wfd))
		return false;
	return (wfd.dwFileAttributes & FileAttributes::Directory) == FileAttributes::Directory;
}
string Directory::GetCurrentDirectory()
{
	string directory;
	directory.resize(PATH_MAX);
	if(::GetCurrentDirectory(PATH_MAX, &directory[0]) == 0)
		return "";
	directory.resize(strlen(directory.c_str()));
	return directory;
}
bool Directory::SetCurrentDirectory(const string& directory)
{
	return ::SetCurrentDirectory(directory.c_str()) != FALSE;
}
bool Directory::GetDirectories(const string& path, vector<string>& directories)
{
	DirectoryString ds(path);
	WIN32_FIND_DATA wfd;
	HANDLE hFind = FindFirstFile((ds.ToString() + "*.*").c_str(), &wfd);
	if(hFind == INVALID_HANDLE_VALUE)
		return false;
	do
	{
		if((wfd.dwFileAttributes & FileAttributes::Directory) == FileAttributes::Directory
			&& strcmp(wfd.cFileName, ".") != 0 && strcmp(wfd.cFileName, "..") != 0)
				directories.push_back(wfd.cFileName);
	}while(FindNextFile(hFind, &wfd));
	FindClose(hFind);
	return true;
}
bool Directory::GetFiles(const string& path, vector<string>& files)
{
	DirectoryString ds(path);
	WIN32_FIND_DATA wfd;
	HANDLE hFind = FindFirstFile((ds.ToString() + "*.*").c_str(), &wfd);
	if(hFind == INVALID_HANDLE_VALUE)
		return false;
	do
	{
		if((wfd.dwFileAttributes & FileAttributes::Directory) == 0)
			files.push_back(wfd.cFileName);
	}while(FindNextFile(hFind, &wfd));
	FindClose(hFind);
	return true;
}

bool DirectoryInfo::GetDirectories(vector<DirectoryInfo>& subDirectories)
{
	DirectoryString ds(directory);
	WIN32_FIND_DATA wfd;
	HANDLE hFind = FindFirstFile((ds.ToString() + "*.*").c_str(), &wfd);
	if(hFind == INVALID_HANDLE_VALUE)
		return false;
	do
	{
		if((wfd.dwFileAttributes & FileAttributes::Directory) == FileAttributes::Directory
			&& strcmp(wfd.cFileName, ".") != 0 && strcmp(wfd.cFileName, "..") != 0)
		{
			subDirectories.push_back(Path::Combine(directory, wfd.cFileName));
		}
	}while(FindNextFile(hFind, &wfd));
	FindClose(hFind);
	return true;
}

bool DirectoryInfo::GetFiles(vector<FileInfo>& files)
{
	DirectoryString ds(directory);
	WIN32_FIND_DATA wfd;
	HANDLE hFind = FindFirstFile((ds.ToString() + "*.*").c_str(), &wfd);
	if(hFind == INVALID_HANDLE_VALUE)
		return false;
	do
	{
		if((wfd.dwFileAttributes & FileAttributes::Directory) == 0)
		{
			files.push_back(Path::Combine(directory, wfd.cFileName));
		}
	}while(FindNextFile(hFind, &wfd));
	FindClose(hFind);
	return true;
}
bool Directory::GetFileSystemEntries(const string& path, vector<string>& entries)
{
	DirectoryString ds(path);
	WIN32_FIND_DATA wfd;
	HANDLE hFind = FindFirstFile((ds.ToString() + "*.*").c_str(), &wfd);
	if(hFind == INVALID_HANDLE_VALUE)
		return false;
	do
	{
		if(strcmp(wfd.cFileName, ".") == 0 || strcmp(wfd.cFileName, "..") == 0)
			continue;
		entries.push_back(wfd.cFileName);
	}while(FindNextFile(hFind, &wfd));
	FindClose(hFind);
	return true;
}
bool Directory::GetLogicalDrives(vector<string>& drives)
{
	string buffer;
	DWORD size = GetLogicalDriveStrings(0, NULL);
	buffer.resize(size + 1);
	GetLogicalDriveStrings(size, &buffer[0]);
	const char * ptr = buffer.c_str();
	while(*ptr != '\0')
	{
		drives.push_back(ptr);
		ptr += strlen(ptr) + 1;
	}
	return true;
}
bool Directory::Move(const string& sourceDirName, const string& destDirName)
{
	return ::MoveFile(sourceDirName.c_str(), destDirName.c_str()) != FALSE;
}


#else		// linux

const string Path::ValidDirectorySeparatorChars("/");

bool FileSystemInfo::GetPathInfo(const string& path, struct stat& info)
{
	return stat(path.c_str(), &info) == 0;
}

bool File::Copy(const string& fromPath, const string& toPath, bool overwrite/* = false*/)
{
	if(!Exists(fromPath))
	{
		return false;
	}
	if(Exists(toPath) && !overwrite)
		return false;
	int64_t length = GetLength(fromPath);
	if(length < 0)
	{
		return false;
	}
	ifstream fin(fromPath.c_str(), ios::in | ios::binary);
	if(!fin)
	{
		return false;
	}
	ofstream fout(toPath.c_str(), ios::out | ios::binary);
	if(!fout)
	{
		fin.close();
		return false;
	}
	const int buf_size = 8192;
	char buffer[buf_size];
	int temp = (int)((length > buf_size) ? buf_size : length);
	fin.read(buffer, temp);
	while(fin && length > 0)
	{
		fout.write(buffer, temp);
		length -= temp;
		temp = (int)((length > buf_size) ? buf_size : length);
		fin.read(buffer, temp);
	}
	fin.close();
	fout.close();
	return true;
}
bool File::Delete(const string& path)
{
	return unlink(path.c_str()) == 0;
}
bool File::Move(const string& sourceFileName, const string& destFileName)
{
	return rename(sourceFileName.c_str(), destFileName.c_str()) == 0;
}
bool File::Exists(const string& path)
{
	struct stat info;
	if(!GetPathInfo(path, info))
		return false;
	return !S_ISDIR(info.st_mode);
}

u_int32_t File::GetAttributes(const string& path)
{
	u_int32_t attributes = 0;
	struct stat info;
	if(!GetPathInfo(path, info))
		return 0;
	if(S_ISDIR(info.st_mode))
		attributes |= FileAttributes::Directory;
	if(S_ISREG(info.st_mode))
		attributes |= FileAttributes::Normal;
	if(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode) || S_ISFIFO(info.st_mode))
		attributes |= FileAttributes::Device;
	return attributes;
}
void File::SetAttributes(const string&, u_int32_t)
{
	// not implemented
	assert(false);
}
int64_t File::GetLength(const string& path)
{
	struct stat info;
	if(!GetPathInfo(path, info))
		return -1;
	return info.st_size;
}
DateTime FileSystemInfo::GetCreationTime(const string& path)
{
	DateTime t = GetCreationTimeUtc(path);
	t.ToLocalTime();
	return t;
}
DateTime FileSystemInfo::GetCreationTimeUtc(const string& path)
{
	struct stat info;
	if(GetPathInfo(path, info))
	{
#ifdef __USE_MISC
		return info.st_ctim;
#else
		timespec ts;
		ts.tv_sec = info.st_ctime;
		ts.tv_nsec = info.st_ctimensec;
		return ts;
#endif
	}
	return DateTime::BadTime();
}
DateTime FileSystemInfo::GetLastAccessTime(const string& path)
{
	DateTime t = GetLastAccessTimeUtc(path);
	t.ToLocalTime();
	return t;
}
DateTime FileSystemInfo::GetLastAccessTimeUtc(const string& path)
{
	struct stat info;
	if(GetPathInfo(path, info))
	{
#ifdef __USE_MISC
		return info.st_atim;
#else
		timespec ts;
		ts.tv_sec = info.st_atime;
		ts.tv_nsec = info.st_atimensec;
		return ts;
#endif
	}
	return DateTime::BadTime();
}
DateTime FileSystemInfo::GetLastWriteTime(const string& path)
{
	DateTime t = GetLastWriteTimeUtc(path);
	t.ToLocalTime();
	return t;
}
DateTime FileSystemInfo::GetLastWriteTimeUtc(const string& path)
{
	struct stat info;
	if(GetPathInfo(path, info))
	{
#ifdef __USE_MISC
		return info.st_mtim;
#else
		timespec ts;
		ts.tv_sec = info.st_mtime;
		ts.tv_nsec = info.st_mtimensec;
		return ts;
#endif
	}
	return DateTime::BadTime();
}

bool Directory::Create(const string& path, bool recursive/* = false */)
{
	if(!recursive)
		return mkdir(path.c_str(), 0) == 0;
	DirectoryString ds(path);
	list<DirectoryStringItem>& items = ds.GetInternalItems();
	list<DirectoryStringItem>::const_iterator it = items.begin();
	string existPath;
	for(; it != items.end(); ++it)
	{
		string temp = existPath + it->GetPureText();
		if(!Directory::Exists(temp))
			break;
		existPath = temp + Path::DirectorySeparatorChar;
	}
	for(; it != items.end(); ++it)
	{
		existPath += it->GetPureText();
		if(mkdir(existPath.c_str(), 0) != 0)
			return false;
		existPath += Path::DirectorySeparatorChar;
	}
	return true;
}
bool Directory::Create(const string& path, DirectoryInfo& di, bool recursive/* = false */)
{
	if(Create(path, recursive))
	{
		di.LoadDirectory(path);
		return true;
	}
	return false;
}
bool Directory::Delete(const string& path, bool recursive/* = false*/)
{
	if(recursive)
	{
		vector<string> names;
		if(!Directory::GetFiles(path, names))
		{
			return false;
		}
		for(size_t i = 0; i < names.size(); ++i)
		{
			if(!File::Delete(Path::Combine(path, names[i])))
			{
				return false;
			}
		}
		names.resize(0);
		if(!Directory::GetDirectories(path, names))
		{
			return false;
		}
		for(size_t i = 0; i < names.size(); ++i)
		{
			if(!Directory::Delete(Path::Combine(path, names[i]), recursive))
			{
				return false;
			}
		}
	}
	return rmdir(path.c_str()) == 0;
}
bool Directory::Exists(const string& path)
{
	struct stat info;
	if(GetPathInfo(path, info))
	{
		return S_ISDIR(info.st_mode);
	}
	return false;
}
string Directory::GetCurrentDirectory()
{
	string directory;
	directory.resize(PATH_MAX);
	if(getcwd(&directory[0], directory.size()) == NULL)
		return "";
	directory.resize(strlen(directory.c_str()));
	return directory;
	
}
bool Directory::SetCurrentDirectory(const string& directory)
{
	return chdir(directory.c_str()) == 0;
}
bool Directory::GetDirectories(const string& path, vector<string>& directories)
{
	DIR* pDir = opendir(path.c_str());
	if(pDir == NULL)
		return false;
	dirent* pEntry = readdir(pDir);
	while(pEntry != NULL)
	{
		if(strcmp(pEntry->d_name, ".") != 0 && strcmp(pEntry->d_name, "..") != 0
			&& FileSystemInfo::IsDirectory(Path::Combine(path, pEntry->d_name)))
		{
			directories.push_back(pEntry->d_name);
		}
		pEntry = readdir(pDir);
	}
	closedir(pDir);
	return true;
}
bool Directory::GetFiles(const string& path, vector<string>& files)
{
	DIR* pDir = opendir(path.c_str());
	if(pDir == NULL)
		return false;
	dirent* pEntry = readdir(pDir);
	while(pEntry != NULL)
	{
		if(FileSystemInfo::IsFile(Path::Combine(path, pEntry->d_name)))
		{
			files.push_back(pEntry->d_name);
		}
		pEntry = readdir(pDir);
	}
	closedir(pDir);
	return true;
}
bool Directory::GetFileSystemEntries(const string& path, vector<string>& entries)
{
	DIR* pDir = opendir(path.c_str());
	if(pDir == NULL)
		return false;
	dirent* pEntry = readdir(pDir);
	while(pEntry != NULL)
	{
		if(strcmp(pEntry->d_name, ".") != 0 && strcmp(pEntry->d_name, "..") != 0)
			entries.push_back(pEntry->d_name);
		pEntry = readdir(pDir);
	}
	closedir(pDir);
	return true;
}

bool DirectoryInfo::GetDirectories(vector<DirectoryInfo>& subDirectories)
{
	DIR* pDir = opendir(directory.c_str());
	if(pDir == NULL)
		return false;
	dirent* pEntry = readdir(pDir);
	while(pEntry != NULL)
	{
		if(strcmp(pEntry->d_name, ".") != 0 && strcmp(pEntry->d_name, "..") != 0
			&& FileSystemInfo::IsDirectory(Path::Combine(directory, pEntry->d_name)))
		{
			subDirectories.push_back(Path::Combine(directory, pEntry->d_name));
		}
		pEntry = readdir(pDir);
	}
	closedir(pDir);
	return true;
}
bool DirectoryInfo::GetFiles(vector<FileInfo>& files)
{
	DIR* pDir = opendir(directory.c_str());
	if(pDir == NULL)
		return false;
	dirent* pEntry = readdir(pDir);
	while(pEntry != NULL)
	{
		string fullname = Path::Combine(directory, pEntry->d_name);
		if(FileSystemInfo::IsFile(fullname))
		{
			files.push_back(fullname);
		}
		pEntry = readdir(pDir);
	}
	closedir(pDir);
	return true;
}
bool Directory::GetLogicalDrives(vector<string>& drives)
{
	drives.push_back("/");
	return true;
}
bool Directory::Move(const string& sourceDirName, const string& destDirName)
{
	return rename(sourceDirName.c_str(), destDirName.c_str()) == 0;
}

#endif		// defined(WIN32)


string Directory::GetDirectoryRoot(const string path)
{
	return Path::GetPathRoot(path);
}

bool Directory::GetParent(const string& path, DirectoryInfo& di)
{
	DirectoryString ds(path);
	if(ds.GotoParent())
	{
		di.LoadDirectory(ds.ToString());
		return true;
	}
	return false;
}


bool Directory::Copy(const string& sourceDir, const string& destDir, bool overwrite/* = false*/)
{
	Create(destDir, true);
	vector<string> names;
	if(!Directory::GetFiles(sourceDir, names))
		return false;
	for(size_t i = 0; i < names.size(); ++i)
	{
		if(!File::Copy(Path::Combine(sourceDir, names[i]), Path::Combine(destDir, names[i]), overwrite))
			return false;
	}
	names.resize(0);
	if(!Directory::GetDirectories(sourceDir, names))
		return false;
	for(size_t i = 0; i < names.size(); ++i)
	{
		if(!Directory::Copy(Path::Combine(sourceDir, names[i]), Path::Combine(destDir, names[i]), overwrite))
			return false;
	}
	return true;
}

bool File::CreateEmptyFile(const string& path)
{
	ofstream fout(path.c_str());
	if(!fout)
		return false;
	fout.close();
	return true;
}

bool File::ReadAllBytes(const string& path, string& bytes)
{
	int64_t length = GetLength(path);
	if(length < 0)
		return false;
	ifstream fin(path.c_str(), ios::binary | ios::in);
	if(!fin)
		return false;
	bytes.resize((string::size_type)length);
	fin.read((char*)&bytes[0], bytes.size());
	fin.close();
	return true;
}
bool File::WriteAllBytes(const string& path, const string& bytes)
{
	ofstream fout(path.c_str(), ios::binary | ios::out);
	if(!fout)
		return false;
	fout.write((const char*)&bytes[0], bytes.size());
	fout.close();
	return true;
}
bool File::AppendAllBytes(const string& path, const string& bytes)
{
	ofstream fout(path.c_str(), ios::binary | ios::out | ios::app);
	if(!fout)
		return false;
	fout.write((const char*)&bytes[0], bytes.size());
	fout.close();
	return true;
}

bool File::ReadAllBytes(const string& path, vector<u_int8_t>& bytes)
{
	int64_t length = GetLength(path);
	if(length < 0)
		return false;
	ifstream fin(path.c_str(), ios::binary | ios::in);
	if(!fin)
		return false;
	bytes.resize((vector<u_int8_t>::size_type)length);
	fin.read((char*)&bytes[0], bytes.size());
	fin.close();
	return true;
}
bool File::WriteAllBytes(const string& path, const vector<u_int8_t>& bytes)
{
	ofstream fout(path.c_str(), ios::binary | ios::out);
	if(!fout)
		return false;
	fout.write((const char*)&bytes[0], bytes.size());
	fout.close();
	return true;
}
bool File::AppendAllBytes(const string& path, const vector<u_int8_t>& bytes)
{
	ofstream fout(path.c_str(), ios::binary | ios::out | ios::app);
	if(!fout)
		return false;
	fout.write((const char*)&bytes[0], bytes.size());
	fout.close();
	return true;
}
bool File::ReadAllLines(const string& path, vector<string>& lines)
{
	ifstream fin(path.c_str());
	if(!fin)
		return false;
	string line;
	getline(fin, line);
	while(!fin)
	{
		lines.push_back(line);
		getline(fin, line);
	}
	fin.close();
	return true;
}
bool File::WriteAllLines(const string& path, const vector<string>& lines)
{
	ofstream fout(path.c_str());
	if(!fout)
		return false;
	for(size_t i = 0; i < lines.size(); ++i)
	{
		fout << lines[i] << endl;
	}
	fout.close();
	return true;
}
bool File::AppendAllLines(const string& path, const vector<string>& lines)
{
	ofstream fout(path.c_str(), ios::out | ios::app);
	if(!fout)
		return false;
	for(size_t i = 0; i < lines.size(); ++i)
	{
		fout << lines[i] << endl;
	}
	fout.close();
	return true;
}
bool File::ReadAllText(const string& path, string& text)
{
	int64_t length = GetLength(path);
	if(length < 0)
		return false;
	ifstream fin(path.c_str(), ios::in);
	if(!fin)
		return false;
	text.resize((string::size_type)length);
	fin.read(&text[0], text.size());
	fin.close();
	return true;
}
bool File::WriteAllText(const string& path, const string& text)
{
	ofstream fout(path.c_str());
	if(!fout)
		return false;
	fout.write(&text[0], text.size());
	fout.close();
	return true;
}
bool File::AppendAllText(const string& path, const string& text)
{
	ofstream fout(path.c_str(), ios::out | ios::app);
	if(!fout)
		return false;
	fout.write(&text[0], text.size());
	fout.close();
	return true;
}




bool Path::IsDirectorySeparatorChar(char c)
{
	return c == DirectorySeparatorChar || c == AltDirectorySeparatorChar;
}

string Path::ChangeExtension(const string& path, const string& extension)
{
	string::size_type index = path.find_last_of('.');
	if(index == string::npos)
		return path + '.' + extension;
	return path.substr(0, index + 1) + extension;
}
string Path::Combine(const string& base, const string& path)
{
	DirectoryString ds(base);
	PathString ps(path);
	ps.AddBaseDirectory(base);
	return ps.ToString();
}
string Path::GetDirectoryName(const string& path)
{
	PathString ps(path);
	return ps.GetDirectoryString().ToString();
}
string Path::GetExtension(const string& path)
{
	string::size_type indexDot = path.find_last_of('.');
	string::size_type indexSlash = path.find_last_of(Path::ValidDirectorySeparatorChars);
	if(indexDot == string::npos || (indexDot <= indexSlash && indexSlash != string::npos))
		return "";
	return path.substr(indexDot);
}
string Path::GetFileName(const string& path)
{
	PathString ps(path);
	return ps.GetFileName();
}
string Path::GetFileNameWithoutExtension(const string& path)
{
	PathString ps(path);
	return ps.GetFileNameWithoutExtension();
}
string Path::GetFullPath(const string& path)
{
	return Combine(Directory::GetCurrentDirectory(), path);
}
string Path::GetPathRoot(const string& path)
{
	PathString ps(path);
	if(ps.IsRooted())
		return ps.GetDirectoryString().GetInternalItems().front().ToString();
	return "";
}
string Path::GetRandomFileName()
{
	static const char candiChars[] = "_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
	static const int candiCount = sizeof(candiChars) / sizeof(candiChars[0]);
	string ret;
	ret.resize(32);
	for(int i = 0; i < 32; ++i)
	{
		ret[i] = candiChars[rand() % candiCount];
	}
	return ret;
}
string Path::GetTempFileName()
{
#ifdef WIN32
	string fileName;
	fileName.resize(PATH_MAX);
	::GetTempFileName(GetTempPath().c_str(), "", 0, &fileName[0]);
	fileName.resize(strlen(fileName.c_str()));
	return fileName;
#else
	DirectoryString ds(GetTempPath());
	int64_t id = DateTime::Now().GetTickCount();
	string fileName = ds.ToString() + ToString(id) + ".TMP";
	while(File::Exists(fileName))
	{
		++id;
		fileName = ds.ToString() + ToString(id) + ".TMP";
	}
	File::CreateEmptyFile(fileName);
	return fileName;
#endif
}
string Path::GetTempPath()
{
#ifdef WIN32
	string path;
	path.resize(PATH_MAX);
	::GetTempPath(PATH_MAX, &path[0]);
	path.resize(strlen(path.c_str()));
	return path;
#else
	return "/tmp";
#endif
}
bool Path::HasExtension(const string& path)
{
	string::size_type indexDot = path.find_last_of('.');
	string::size_type indexSlash = path.find_last_of(Path::ValidDirectorySeparatorChars);
	return indexDot != string::npos && (indexDot > indexSlash || indexSlash == string::npos);
}
bool Path::IsPathRooted(const string& path)
{
	PathString ps(path);
	return ps.IsRooted();
}

}
}

